package controllers

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"lottery/bootstrap"
	"lottery/comm"
	"lottery/conf"
	"lottery/models"
	"lottery/services"
	"lottery/utils"
	"net/http"
	"strconv"
	"strings"
)

// 后台优惠券管理控制器创建
type AdminCodeController struct {
	ServiceUser    services.UserService
	ServiceGift    services.GiftService
	ServiceCode    services.CodeService
	ServiceResult  services.ResultService
	ServiceUserday services.UserdayService
	ServiceBlackip services.BlackipService
}

// adcc adminCodeController
// 这个 Get方法， 既处理 单一查询，也处理多查询
func (adcc *AdminCodeController) Get(c *gin.Context) {
	// 获取url 中的参数, id, page, 并转为int类型
	giftId, _ := strconv.Atoi(c.DefaultQuery("gift_id", "0"))
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	size := 10 // 默认页面大小为 100
	// 数据列表构建, 总数
	var (
		total    int
		pagePrev string // 上下页码
		pageNext string
		datalist []models.LtCode
		// 数量， 缓存数量
		num      int
		cacheNum int
	)
	// 进行判断是单个查询还是 总数
	if giftId > 0 {
		datalist = adcc.ServiceCode.Search(giftId, page, size)
		// 增加缓存
		num, cacheNum = utils.GetCacheCodeNum(giftId, adcc.ServiceCode)
	} else { // 全查: 分页
		datalist = adcc.ServiceCode.GetAll(page, size)
	}
	// 优化总数查询，当前页数据不满 size 时， 直接计算，不必访问数据库一次了。
	total = (page-1)*size + len(datalist)
	// 总数（表示所有数量）上面可能计算的不是准确的， 因为 可能还有下一页
	if len(datalist) >= size {
		if giftId > 0 {
			total = int(adcc.ServiceCode.CountByGift(giftId)) // int64 转 int
		} else {
			total = int(adcc.ServiceCode.CountAll())
		}
		// 计算下一页页码
		pageNext = fmt.Sprintf("%d", page+1)
	}
	// 计算上一页
	if page > 1 {
		pagePrev = fmt.Sprintf("%d", page-1)
	}
	// 返回
	c.HTML(http.StatusOK, "admin/code", gin.H{
		"Title":    "后台管理",
		"Channel":  "code",
		"GiftId":   giftId,
		"Datalist": datalist,
		"Total":    total,
		"PagePrev": pagePrev,
		"PageNext": pageNext,
		"CodeNum":  num, // 数据不一致，说明有出入，需要重置
		"CacheNum": cacheNum,
	})

}

// 数据的导入
func (adcc *AdminCodeController) PostImport(c *gin.Context) {
	//导入优惠券， 首先需要知道 优惠券所在的奖品
	giftId, _ := strconv.Atoi(c.DefaultQuery("gift_id", "0"))
	if giftId < 1 {
		// 出错, 创建一个错误对象吧
		err := bootstrap.Error{"后端管理", http.StatusForbidden,
			"没有指定奖品ID, 无法进行导入"}
		c.JSON(http.StatusOK, gin.H{
			"status": "NO",
			"error":  err,
		})
		return
	}
	gift, ok := adcc.ServiceGift.Get(giftId, true)
	// 如果不存在gift，或者 gift 不是差异化的虚拟券， 返回错误信息
	fmt.Println(ok)
	if !ok || gift.Gtype != conf.GtypeCodeDiff {
		c.JSON(http.StatusOK, gin.H{
			"status": "NO",
			"error":  "奖品信息不存在或者奖品类型不是差异化优惠券， 无法进行导入",
		})
		return
	}
	fmt.Println(123123)
	// post 请求中，拿到 codes 信息
	codes := c.DefaultPostForm("codes", "")
	// 获取当前时间，int类型
	now := comm.NowUnix()
	// 换行符分割每一个券
	list := strings.Split(codes, "\n")
	// 成功 失败导入的数量
	var (
		sucNum int
		errNum int
	)
	for _, code := range list {
		// 去空格
		code := strings.TrimSpace(code)
		if code != "" {
			// 创建结构
			data := &models.LtCode{
				GiftId:     giftId,
				Code:       code,
				SysCreated: now,
			}
			// 存数据库
			err := adcc.ServiceCode.Create(data)
			// 计数
			if err != nil {
				errNum++
			} else {
				sucNum++
				// 成功导入数据库，可能还有下一步的操作：导入缓存
				ok := utils.ImportCacheCodes(giftId, code)
				if ok {
					sucNum++
				} else {
					errNum++
				}
			}
		}
	}
	// TODO: 输出HTML代码
	c.String(http.StatusOK, fmt.Sprintf("成功导入：%d 条数据, 失败：%d 条数据<a href='/admin/code/%d'></a>",
		sucNum, errNum, giftId))
}

// 数据的删除: 状态改为 1
func (adcc *AdminCodeController) GetDelete(c *gin.Context) {
	// 获取url中的id值
	id, err := strconv.Atoi(c.Query("id"))
	if err == nil { // 设置默认值为 0
		// 执行删除
		adcc.ServiceCode.Delete(id)
	}
	// 恢复成功了，也跳转
	c.Redirect(http.StatusFound, "/admin/code")
}

// 数据恢复： 状态改为 0
func (adcc *AdminCodeController) GetReset(c *gin.Context) {
	// 获取路径中的id值
	id, err := strconv.Atoi(c.Query("id"))
	if err == nil { // 设置默认值为 0
		// 执行恢复
		adcc.ServiceCode.Update(&models.LtCode{Id: id, SysStatus: 0}, []string{"sys_status"})
	}

	// 恢复成功了，也跳转
	c.Redirect(http.StatusFound, "/admin/code")
}

// 增加方法， 手动整理，缓存中的数据
func (adcc *AdminCodeController) GetRecache(c *gin.Context) {
	refer := c.Request.Header.Get("Referer")
	if refer == "" {
		refer = "/admin/code"
	}
	id, err := strconv.Atoi(c.Query("id"))
	if err != nil || id < 1 {
		rs := fmt.Sprintf("没有指定优惠券所属的奖品id，<a href='%s'>点击跳转</a>", refer)
		c.String(http.StatusOK, rs)
		return
	}
	sucNum, errNum := utils.RecacheCodes(id, adcc.ServiceCode)
	rs := fmt.Sprintf("sucNum=%d, errNum=%d, <a href='%s'></a>",
		sucNum, errNum, refer)
	c.String(http.StatusOK, rs)
}
